package org.action.order.sercive.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.seata.core.context.RootContext;
import io.seata.spring.annotation.GlobalTransactional;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.PreDestroy;

import org.action.order.domain.entity.ActionTicketUser;
import org.action.order.domain.pojo.ActionOrder;
import org.action.order.mapper.ActionTicketUserMapper;
import org.action.order.sercive.IActionTicketUserService;
import org.action.order.util.StreamRedisList;
import org.common.util.JwtUtils;
import org.common.util.RedisCommon;
import org.common.util.Result;
import org.common.util.ThreadlocalUtils;
import org.museum.api.client.ActionCommonClient;
import org.museum.api.client.ActionInventoryClient;
import org.museum.api.client.IdentityNameClient;
import org.museum.api.domain.Action;
import org.museum.api.util.CommonResponse;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static org.action.order.util.StaticVariable.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zafkiel
 * @since 2025-06-22
 */
@Service
public class ActionTicketUserServiceImpl extends ServiceImpl<ActionTicketUserMapper, ActionTicketUser> implements IActionTicketUserService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedisCommon redisCommon;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private IdentityNameClient identityNameClient;
    @Autowired
    private ActionInventoryClient actionInventoryClient;
    @Autowired
    private ActionCommonClient actionCommonClient;
    //@Autowired
    //private StreamRedisList streamRedisList;
    //@Autowired
    //private ActionOrderProcessingService actionOrderProcessingService;

    //获取一个阻塞队列
    //private final BlockingQueue<ActionOrder> blockingQueue = new LinkedBlockingQueue<>();
    //获取一个单核线程池
    //private final ThreadPoolExecutor executor = new ThreadPoolExecutor(1,1,1000, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>());
    //获取lua脚本
    private static final DefaultRedisScript<Long> Action_Script;


    //线程池初始化和关闭线程池
    /*
    @PostConstruct
    //初始化线程池
    public void init() {
        // 初始化代理对象
        executor.submit(new ActionOrderThread());
    }
    @PreDestroy
    //关闭线程池
    public void shutdown() {
        executor.shutdown(); // 优雅关闭
        try {
            if (!executor.awaitTermination(20, TimeUnit.SECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
            Thread.currentThread().interrupt();
        }
    }

     */

    //创建一个线程从阻塞队列中取出订单，并执行活动库存扣减操作
    /*
    private class ActionOrderThread implements Runnable{
        @Override
        public void run() {
            while (true){
                //从阻塞队列中取出订单
                try {
                    //方法一从阻塞队列里取订单
                    //ActionOrder actionOrder = blockingQueue.take();
                    //方案二从redis的list消息队列里取订单
                    //ActionOrder actionOrder = redisCommon.getFromMessageQueue(Action_Order_Queue, ActionOrder.class);
                    //方案三从redis的stream队列里取订单
                    processPendingMessages();
                    List<Map<String, ActionOrder>> actionOrders=streamRedisList.getFromMessageQueue(20,"zafkiel", ActionOrder.class);
                    if(actionOrders==null||actionOrders.isEmpty()){
                        //如果没有订单，则继续循环
                        continue;
                    }
                    for(Map<String, ActionOrder> map:actionOrders){
                        for (String key:map.keySet()) {
                            System.out.println("线程" + Thread.currentThread().getName() + "正在处理订单" + map.get( key));
                            try {
                                actionOrderProcessingService.deductActionTicket(map.get(key));
                                //确认消息
                                System.out.println("确认消息"+ key);
                                streamRedisList.confirmMessage(key);
                            } catch (Exception e) {
                                log.error("处理订单失败{}",e);
                                //从pending中取消息
                                processPendingMessages();
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("处理订单失败{}",e);
                }
            }
        }
    }

    //从pedding中获取消息
    private void processPendingMessages() {
        int retryCount = 0;
        while (true) {
            try {
                // ===== 添加连接状态检查 =====
                if (!streamRedisList.isRedisAvailable()) {
                    log.warn("Redis不可用，暂停处理消息");
                    Thread.sleep(5000); // 等待5秒重试
                    continue;
                }
                List<Map<String, ActionOrder>> actionOrderPeddings=streamRedisList.processPendingMessages("zafkiel", ActionOrder.class);
                if(actionOrderPeddings==null || actionOrderPeddings.isEmpty()) break;
                for (Map<String, ActionOrder> actionOrderMap:actionOrderPeddings) {
                    for (String k:actionOrderMap.keySet()) {
                        System.out.println("haha线程" + Thread.currentThread().getName() + "正在处理订单" + actionOrderMap.get(k));
                        try {
                            ActionOrder actionOrder=actionOrderMap.get(k);
                            actionOrderProcessingService.deductActionTicket(actionOrder);
                            //确认消息
                            streamRedisList.confirmMessage(k);
                        } catch (Exception e) {
                            retryCount++;
                            if(retryCount > 3) break;
                            log.error("处理订单失败{}", e);
                            //从pending中取消息
                        }
                    }
                }
                break;
            }catch (Exception e) {
                log.error("处理订单失败{}", e);
            }
        }
    }

     */

    //静态初始化lua脚本
    static {
        Action_Script = new DefaultRedisScript<>();
        Action_Script.setLocation(new ClassPathResource("ActionTicket.lua"));
        Action_Script.setResultType(Long.class);
    }
    @Override
    @Transactional
    public Result saveActionOrder(ActionOrder actionOrder) {
        //获取当前线程的jwt
        String jwt = ThreadlocalUtils.get();
        //获取当前线程的电话
        actionOrder.setPhone(JwtUtils.getJwtUsername(jwt));
        //执行lua脚本
        Long result = stringRedisTemplate.execute(Action_Script,
                Collections.emptyList(),
                actionOrder.getActionTicketId().toString(), actionOrder.getRelativeIdentity(), actionOrder.getChildrenIdentity());
        int r = 0;
        if (result != null) {
            r = result.intValue();
        }
        System.out.println(r);
        if (r != 0) {
            if (r == 1) return Result.error("活动已报名满");
            if (r == 2) return Result.error("大人已购买");
            if (r == 3) return Result.error("小孩已购买");
        }
        //将订单放入阻塞队列
        Long orderId;
        orderId = redisCommon.nextId(Action_Ticket_Id + actionOrder.getActionTicketId());
        actionOrder.setId(orderId);
        System.out.println("订单号："+orderId);
        //方法一：放入阻塞队列
        //blockingQueue.put(actionOrder);
        //方法二：放入redis的list的消息队列
        //redisCommon.addToMessageQueue(Action_Order_Queue,actionOrder);
        //方法三：放入redis的stream的消息队列
        //streamRedisList.addToMessageQueue(actionOrder);
        //方法四：放入rabbitmq的消息队列
        rabbitTemplate.convertAndSend(Action_Order_Exchange,Action_Order_Routing_Key,actionOrder);
        //给延迟队列发送消息
        rabbitTemplate.convertAndSend(Action_Order_Delay_Exchange,Action_Order_Routing_Delay_Key,orderId,message -> {
            message.getMessageProperties().setDelayLong((long) (1000 * 60 * 15));
            return message;
        });
        System.out.println("放入成功");
        return Result.success("订单提交成功",orderId+"");
    }

    @Override
    public Result getActionOrderById(Long orderId) {
        ActionOrder actionOrder=new ActionOrder();
        //获取订单
        ActionTicketUser actionTicketUser=baseMapper.selectById(orderId);
        //根据用户名身份证查询姓名
        CommonResponse<String> relativeName = identityNameClient.getIdentityName(actionTicketUser.getRelativeIdentity());
        System.out.println(relativeName);
        //获取大人姓名
        actionOrder.setRelativeName(relativeName.getData());
        CommonResponse<String> childrenName = identityNameClient.getIdentityName(actionTicketUser.getChildrenIdentity());
        System.out.println(childrenName);
        //获取小孩姓名
        actionOrder.setChildrenName(childrenName.getData());
        //使用胡图工具包把actionTicketUser的属性赋值给actionOrder
        BeanUtils.copyProperties(actionTicketUser,actionOrder);
        System.out.println(actionOrder);

        //获取活动信息
        CommonResponse<Integer> actionId = actionInventoryClient.getActionIdById(actionTicketUser.getActionTicketId());
        //根据id获取详细活动详细信息
        CommonResponse<Action> action = actionCommonClient.getActionById(actionId.getData());
        Result result = Result.success();
        result.put("action",action.getData());
        result.put("order",actionOrder);
        return result;
    }
}
